﻿using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;

namespace Kkbac.Tools.Mobile
{ 
    public class DeviceDetect
    {
        // mobile phone user agent array
        public static string[] mobiUserAgents = new string[] { "1207", "3gso", "4thp", "501i", "502i", "503i", "504i", "505i", 
            "506i", "6310", "6590", "770s", "802s", "a wa", "acer", "acs-", "airn", "alav", "asus", "attw", "au-m", "aur ", 
            "aus ", "abac", "acoo", "aiko", "alco", "alca", "amoi", "anex", "anny", "anyw", "aptu", "arch", "argo", "bell", 
            "bird", "bw-n", "bw-u", "beck", "benq", "bilb", "blac", "c55/", "cdm-", "chtm", "capi", "cond", "craw", "dall", 
            "dbte", "dc-s", "dica", "ds-d", "ds12", "dait", "devi", "dmob", "doco", "dopo", "el49", "erk0", "esl8", "ez40", 
            "ez60", "ez70", "ezos", "ezze", "elai", "emul", "eric", "ezwa", "fake", "fly-", "fly_", "g-mo", "g1 u", "g560", 
            "gf-5", "grun", "gene", "go.w", "good", "grad", "hcit", "hd-m", "hd-p", "hd-t", "hei-", "hp i", "hpip", "hs-c", 
            "htc ", "htc-", "htca", "htcg", "htcp", "htcs", "htct", "htc_", "haie", "hita", "huaw", "hutc", "i-20", "i-go", 
            "i-ma", "i230", "iac", "iac-", "iac/", "ig01", "im1k", "inno", "iris", "jata", "java", "kddi", "kgt", "kgt/", 
            "kpt ", "kwc-", "klon", "lexi", "lg g", "lg-a", "lg-b", "lg-c", "lg-d", "lg-f", "lg-g", "lg-k", "lg-l", "lg-m", 
            "lg-o", "lg-p", "lg-s", "lg-t", "lg-u", "lg-w", "lg/k", "lg/l", "lg/u", "lg50", "lg54", "lge-", "lge/", "lynx", 
            "leno", "m1-w", "m3ga", "m50/", "maui", "mc01", "mc21", "mcca", "medi", "meri", "mio8", "mioa", "mo01", "mo02", 
            "mode", "modo", "mot ", "mot-", "mt50", "mtp1", "mtv ", "mate", "maxo", "merc", "mits", "mobi", "motv", "mozz", 
            "n100", "n101", "n102", "n202", "n203", "n300", "n302", "n500", "n502", "n505", "n700", "n701", "n710", "nec-", 
            "nem-", "newg", "neon", "netf", "noki", "nzph", "o2 x", "o2-x", "opwv", "owg1", "opti", "oran", "p800", "pand", 
            "pg-1", "pg-2", "pg-3", "pg-6", "pg-8", "pg-c", "pg13", "phil", "pn-2", "pt-g", "palm", "pana", "pire", "pock", 
            "pose", "psio", "qa-a", "qc-2", "qc-3", "qc-5", "qc-7", "qc07", "qc12", "qc21", "qc32", "qc60", "qci-", "qwap", 
            "qtek", "r380", "r600", "raks", "rim9", "rove", "s55/", "sage", "sams", "sc01", "sch-", "scp-", "sdk/", "se47", 
            "sec-", "sec0", "sec1", "semc", "sgh-", "shar", "sie-", "sk-0", "sl45", "slid", "smb3", "smt5", "sp01", "sph-", 
            "spv ", "spv-", "sy01", "samm", "sany", "sava", "scoo", "send", "siem", "smar", "smit", "soft", "sony", "t-mo", 
            "t218", "t250", "t600", "t610", "t618", "tcl-", "tdg-", "telm", "tim-", "ts70", "tsm-", "tsm3", "tsm5", "tx-9", 
            "tagt", "talk", "teli", "topl", "hiba", "up.b", "upg1", "utst", "v400", "v750", "veri", "vk-v", "vk40", "vk50", 
            "vk52", "vk53", "vm40", "vx98", "virg", "vite", "voda", "vulc", "w3c ", "w3c-", "wapj", "wapp", "wapu", "wapm", 
            "wig ", "wapi", "wapr", "wapv", "wapy", "wapa", "waps", "wapt", "winc", "winw", "wonu", "x700", "xda2", "xdag", 
            "yas-", "your", "zte-", "zeto", "acs-", "alav", "alca", "amoi", "aste", "audi", "avan", "benq", "bird", "blac", 
            "blaz", "brew", "brvw", "bumb", "ccwa", "cell", "cldc", "cmd-", "dang", "doco", "eml2", "eric", "fetc", "hipt", 
            "http", "ibro", "idea", "ikom", "inno", "ipaq", "jbro", "jemu", "java", "jigs", "kddi", "keji", "kyoc", "kyok", 
            "leno", "lg-c", "lg-d", "lg-g", "lge-", "libw", "m-cr", "maui", "maxo", "midp", "mits", "mmef", "mobi", "mot-", 
            "moto", "mwbp", "mywa", "nec-", "newt", "nok6", "noki", "o2im", "opwv", "palm", "pana", "pant", "pdxg", "phil", 
            "play", "pluc", "port", "prox", "qtek", "qwap", "rozo", "sage", "sama", "sams", "sany", "sch-", "sec-", "send", 
            "seri", "sgh-", "shar", "sie-", "siem", "smal", "smar", "sony", "sph-", "symb", "t-mo", "teli", "tim-", "tosh", 
            "treo", "tsm-", "upg1", "upsi", "vk-v", "voda", "vx52", "vx53", "vx60", "vx61", "vx70", "vx80", "vx81", "vx83", 
            "vx85", "wap-", "wapa", "wapi", "wapp", "wapr", "webc", "whit", "winw", "wmlb", "xda-"
        };

        public static bool IsAndroid()
        {
            var deviceType = DeviceType.OtherMobile;
            var status = "";
            var b = Detect(out deviceType, out status);

            var isAndroid = (deviceType == DeviceType.Android);

            return isAndroid;
        }

        /// <summary>
        /// True 为移动设备; False 为PC
        /// </summary>
        /// <returns>True 为移动设备; False 为PC</returns>
        public static bool IsMobile()
        {
            var deviceType = DeviceType.OtherMobile;
            var status = "";
            var b = Detect(out deviceType, out status);
            return b;
        }

        /// <summary>
        /// 检测是否为手机, 
        /// </summary>
        /// <param name="deviceType">设备类型</param>
        /// <param name="status">匹配结果</param>
        /// <returns>True 为移动设备; False 为PC</returns>
        public static bool Detect(out DeviceType deviceType, out string status)
        {
            bool isMobile = true;

            deviceType = DeviceType.OtherMobile;

            var _SERVER = HttpContext.Current.Request.ServerVariables;

            var user_agent = _SERVER["HTTP_USER_AGENT"] + "";
            var accept = _SERVER["HTTP_ACCEPT"] + "";

            if (user_agent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                deviceType = DeviceType.iPad;
                status = "Apple iPad";
            }
            else if (user_agent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) >= 0
               || user_agent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) >= 0
               || user_agent.IndexOf("ios", StringComparison.OrdinalIgnoreCase) >= 0
            )
            {
                deviceType = DeviceType.iPhone;
                status = "Apple";
            }
            else if (user_agent.IndexOf("android", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                deviceType = DeviceType.Android;
                status = "Android";
            }
            else if (user_agent.IndexOf("Adr", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                deviceType = DeviceType.Android;
                status = "Android";
            }
            else if (user_agent.IndexOf("opera mini", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                deviceType = DeviceType.Opera;
                status = "Opera";
            }
            else if (user_agent.IndexOf("blackberry", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                deviceType = DeviceType.Blackberry;
                status = "Blackberry";
            }
            else if (user_agent.IndexOf("windows phone os", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                deviceType = DeviceType.WindowsPhone;
                status = "Windows Phone";
            }
            else if (Regex.IsMatch(user_agent, @"(pre/|palm os|palm|hiptop|avantgo|plucker|xiino|blazer|elaine)", RegexOptions.IgnoreCase))
            {
                deviceType = DeviceType.Palm;
                status = "Palm";
            }
            else if (Regex.IsMatch(user_agent, @"(iris|3g_t|windows ce|opera mobi|windows ce; smartphone;|windows ce; iemobile)", RegexOptions.IgnoreCase))
            {
                deviceType = DeviceType.WindowsMobile;
                status = "Windows Smartphone";
            }
            else if (Regex.IsMatch(user_agent, @"(mini 9.5|vx1000|lge |m800|e860|u940|ux840|compal|wireless| mobi|ahong|lg380|lgku|lgu900|lg210|lg47|lg920|lg840|lg370|sam-r|mg50|s55|g83|t66|vx400|mk99|d615|d763|el370|sl900|mp500|samu3|samu4|vx10|xda_|samu5|samu6| samu7|samu9|a615|b832|m881|s920|n210|s700|c-810|_h797|mob-x|sk16d|848b|mowser|s580|r800|471x|v120|rim8|c500foma:|160x|x160|480x|x640|t503|w839|i250|sprint| w398samr810|m5252|c7100|mt126|x225|s5330|s820|htil-g1|fly v71|s302|-x113|novarra|k610i|-three|8325rc|8352rc|sanyo|vx54|c888|nx250|n120|mtk |c5588|s710|t880|c5005|i;458x|p404i|s210|c5100|teleca|s940|c500|s590|foma|samsu|vx8|vx9|a1000| _mms|myx|a700|gu1100|bc831|e300|ems100|me701|me702m-three|sd588|s800|8325rc|ac831|mw200|brew |d88|htc/|htc_touch|355x|m50|km100|d736|p-9521|telco|sl74|ktouch|m4u/|me702|8325rc|kddi|phone|lg |sonyericsson|samsung|240x|x320|vx10|nokia|sony cmd|motorola|up.browser|up.link|mmp|symbian|smartphone|midp|wap|vodafone|o2|pocket|kindle|mobile|psp|treo)", RegexOptions.IgnoreCase))
            {
                deviceType = DeviceType.OtherMobile;
                status = "Mobile matched on piped regex match";
            }
            else if (accept.IndexOf("text/vnd.wap.wml") >= 0 || accept.IndexOf("application/vnd.wap.xhtml+xml") >= 0)
            {
                deviceType = DeviceType.OtherMobile;
                status = "Mobile matched on content accept header";
            }
            else if (_SERVER["HTTP_X_WAP_PROFILE"] != null || _SERVER["HTTP_PROFILE"] != null)
            {
                deviceType = DeviceType.OtherMobile;
                status = "Mobile matched on profile headers being set";
            }
            else if (mobiUserAgents.Contains(user_agent.Substring(0, 4).ToLower()))
            {
                deviceType = DeviceType.OtherMobile;
                status = "Mobile matched on user agent array";
            }
            else
            {
                deviceType = DeviceType.PC;
                status = "Desktop / full capability browser";
                isMobile = false;
            }

            return isMobile;
        }

        /// <summary>
        /// 设备类型
        /// </summary>
        public enum DeviceType
        {
            iPhone,
            iPad,
            Android,
            Opera,
            Blackberry,
            Palm,
            WindowsMobile,
            WindowsPhone,
            OtherMobile,
            PC,
        }
    }

}
